/********************************************************************************
* writer: SDJ
* create date: 2017-7-15
* description:基础服务类，封装了APP常用的公共方法。如日志打印、AJAX请求、状态提示等
* rewriter: SDJ
* rewrite date: 2017-7-21
* description:
*   1.SERVICE封装中增加了MD5,SHA1 同步加密方法;
*   2.修改了fixStatusBar()中修改对象为header标签;
* rewrite date: 2017-8-5
* description:
*   1.增加图片缓存懒加载方法 fnCacheImage(pEl);

*********************************************************************************/
/******************************************
                对象操作方法
******************************************/
//从其他JSON对象中获取JSON对象的属性增加给目标对象（p）

function fnAddAttributesFromOtherObj(pObj, pOtherObj) {
    var tObj = pObj;
    if ('[object Object]' !== Object.prototype.toString.call(pObj) || '[object Object]' !== Object.prototype.toString.call(pOtherObj)) {
        console.log('fnAddAttributesFromOtherObj函数 输入参数类型错误')
        return;
    }
    for (var key in pOtherObj) {
        var tValue = pOtherObj[key];
        if ('[object Object]' === Object.prototype.toString.call(tValue) && '[object Object]' === Object.prototype.toString.call(pObj[key])) {
            tObj[key] = arguments.callee(tObj[key], tValue);
        } else {
            tObj[key] = tValue;
        }
    }
    return tObj;
}

//数组
//获取对象在数组中的索引位置，对象不存在，则返回-1，可间接判断一个对象是否为数组成员
function isInArray(pObj, pArray) {
    if ('[object Array]' !== Object.prototype.toString.call(pArray)) {
        return;
    }
    for (var i = 0; i < pArray.length; i++) {
        if (pObj == self[i]) {
            return i;
        }
    }
    return -1;
}
/******************************************
                UI界面类方法
******************************************/

//修复沉浸式头部高度
function fixStatusBar() {
   var el = document.querySelector('header');
    if (!el) {
        return;
    }
    el.style.paddingTop = api.safeArea.top + "px";
    window.headerHeight = el.offsetHeight; // 获取header高度
    window.paddingTop = api.safeArea.top;
}
//修复沉浸式底部高度(自动执行方法)
function fixFooterBtn() {
   var el = document.querySelectorAll('.bottom-btns');
   if (!el) {
        return;
    }
    for(var i=0;i<el.length;i++){
      var curH = $api.offset(el[i]).h;
      el[i].style.height = curH + USER.Get('safeBottom',true) + "px";
    }
}

// //窗口加载处理
// window.onload = function() {
//     fixStatusBar();
// }

// 获取元素相对于屏幕的rect;
/**
 * 获取元素相对于屏幕的rect;
 * @param  {HTMLElement} pEl    目标元素
 * @param  {HTMLElement} pStopEl [可选，终止条件元素，当遍历父元素与终止条件元素相同是，结束循环]
 * @return {JSON}         元素相对屏幕的rectJSON对象  {x: 10, y: 20, w: 200, h: 100};
 */
function fnGetElRect(pEl, pStopEl) {
    var tEl_x = 0,
        tEl_y = 0,
        tEl_w, tEl_h;
    var tObj = pEl;
    tEl_w = tObj.offsetWidth;
    tEl_h = tObj.offsetHeight;
    while (tObj && tObj != pStopEl) {
        console.log(tObj.nodeName + '----tObj.offsetTop==' + tObj.offsetTop);
        if (tObj.offsetLeft) {
            tEl_x += tObj.offsetLeft;
        }
        if (tObj.offsetTop) {
            tEl_y += tObj.offsetTop;
        }
        tObj = tObj.parentNode;
    }
    return {
        x: tEl_x,
        y: tEl_y,
        w: tEl_w,
        h: tEl_h
    };
}

/**
 * 图片懒加载缓存处理
 * @param  {Object} pEl 页面图片img元素
 * 说明: 在img元素的src路径设置默认的图片，将真正的图片url放入img元素的data-src属性中，同在在img元素中增加onload="fnCacheImage(this);"事件
 *    如 <img onload="fnCacheImage(this);" data-src="{{=it.imgsrc}}" src="../image/defaults/default.jpg" alt="">
 */
function fnCacheImage(pEl) {
    if (!pEl) {
        return;
    }
    var tEl = pEl;
    var tSrc = tEl.dataset.src;
    // LOG('fnCacheImage src=='+tSrc);
    if (!tSrc || tSrc == 'null' || tSrc == 'undefined') {
        return;
    }
    tEl.onload = null;
    api.imageCache({
        url: tSrc
    }, function(ret, err) {
        tEl.src = 'http://' + ret.url;
    });
}


// 等待状态提示
function Loading() {
    var _UILoading = api.require("UILoading");
    var _id;
    // this.Show = function() { // 默认动画
    //     _UILoading.flower({
    //       center : {
    //         x : api.winWidth / 2.0,
    //         y : api.winWidth / 2.0 + 50,
    //       },
    //       size : 20,
    //       fixed : true
    //     }, function(ret) {
    //       _id = ret.id;
    //     });
    // };
    // this.Close = function() {
    //     _UILoading.closeFlower({
    //       id : _id
    //     });
    // }
    // var _content = [{frame:'widget://image/loading/loading-1.png'},{frame:'widget://image/loading/loading-10.png'}];
    var _content = [];
    for (var i = 1; i < 10; i++) {
        var tPath = 'widget://image/load/' + i + '.png';
        _content.push({
            'frame': tPath
        });
    }
    this.Show = function() { //自定义动画
        _UILoading.keyFrame({
            rect: {
                w: 80,
                h: 80
            },
            styles: {
                bg: 'rgba(0,0,0,0)',
                corner: 0,
                interval: 400,
                frame: {
                    w: 80,
                    h: 80
                }
            },
            content: _content,
            mask: 'rgba(0,0,0,0.1)'
        }, function(ret) {

        });
    };
    this.Close = function() {
        _UILoading.closeKeyFrame();
    }
}
// 系统提示框
function fnAlert(pParamJSON, pCallBack) {
    if ('[object Object]' !== Object.prototype.toString.call(pParamJSON)) {
        return;
    }
    var tTitle = pParamJSON.title ? pParamJSON.title : '系统提示';
    var tMsg = pParamJSON.msg ? pParamJSON.msg : '';

    api.alert({
        title: tTitle,
        msg: tMsg,
    }, function(ret, err) {
        if ('function' == typeof pCallBack) {
            pCallBack();
        }
    });
}

// 下载刷新方法封装（使用UIPullRefreshFlash模块）
function fnAddHeaderRefreshingEvent(pCallBack) {
    var _content = [];
    for (var i = 1; i < 10; i++) {
        var tPath = 'widget://image/loading/loading-' + i + '.png';
        _content.push({
            'frame': tPath
        });
    }
    api.setCustomRefreshHeaderInfo({
        bgColor: 'rgba(0,0,0,0)',
        image: {
            pull: [
                'widget://image/loading/1.png',
                'widget://image/loading/2.png',
                'widget://image/loading/3.png',
                'widget://image/loading/4.png',
                'widget://image/loading/5.png',
                'widget://image/loading/6.png',
                'widget://image/loading/7.png',
                'widget://image/loading/8.png',
                'widget://image/loading/9.png',
                'widget://image/loading/10.png',
                'widget://image/loading/11.png',
                'widget://image/loading/12.png',
                'widget://image/loading/13.png'
            ],
            load: [
                'widget://image/loading/13.png',
                'widget://image/loading/12.png',
                'widget://image/loading/11.png',
                'widget://image/loading/10.png',
                'widget://image/loading/9.png',
                'widget://image/loading/8.png',
                'widget://image/loading/7.png',
                'widget://image/loading/6.png',
                'widget://image/loading/5.png',
                'widget://image/loading/4.png',
                'widget://image/loading/3.png',
                'widget://image/loading/2.png',
                'widget://image/loading/1.png'
            ]
        }
    }, function(ret, err) {
        if ('function' === typeof pCallBack) {
            pCallBack();
        }
    });
    // api.setCustomRefreshHeaderInfo({
    //     bgColor: 'rgba(0,0,0,0)',
    //     isScale: true,
    //     image: {
    //         pull: _content,
    //         load: _content
    //     }
    // }, function() {
    //     if('function' === typeof pCallBack) {
    //         pCallBack();
    //     }
    // });
}
// 上拉加载方法封装
function fnAddFooterLoadingEvent(pCallBack) {
    api.addEventListener({
        name: 'scrolltobottom',
        extra: {
            threshold: 50 //设置距离底部多少距离时触发，默认值为0，数字类型
        }
    }, function(ret, err) {
        var tFrameH = api.frameHeight;
        var tHtml = $api.dom('html');
        var tHtmlH = $api.cssVal(tHtml, 'height');
        if(parseInt(tFrameH)<(parseInt(tHtmlH)+200)){
          if ('function' === typeof pCallBack) {
              pCallBack();
          }
        }
    });
}

var DURATION = 300; //窗口动画持续时间

function fnOpenWin(pParamJSON) {
    var _conf = {
        scrollToTop: false,
        vScrollBarEnabled: false,
        hScrollBarEnabled: false,
        slidBackEnabled: false,
        softInputMode: 'resize',
        // animation: {type: 'push', subType:"from_right", duration: DURATION},
        delay: 0,
        reload: true
    };
    if ('[object Object]' == Object.prototype.toString.call(pParamJSON)) {
        fnAddAttributesFromOtherObj(_conf, pParamJSON);
    }
    api.openWin(_conf);
}

function fnCloseToWin(pParamJSON) {
    _conf = {
        // animation: {
        //     type: {type: 'push', subType:"from_right", duration: DURATION}
        // }
    };
    if ('[object Object]' == Object.prototype.toString.call(pParamJSON)) {
        fnAddAttributesFromOtherObj(_conf, pParamJSON);
    }
    api.closeToWin(_conf);
}

function fnOpenFrame(pParamJSON) {
    var frameY = 0;

    if (window.headerHeight) {
        frameY = window.headerHeight;
    }
    var _conf = {
        rect: {
            x: 0,
            y: frameY,
            w: 'auto',
            h: 'auto'
        },
        scrollToTop: false,
        vScrollBarEnabled: false,
        hScrollBarEnabled: false,
        animation: {
            type: 'none'
        },
        softInputMode: 'resize',
        delay: 0,
        reload: true
    };
    if ('[object Object]' == Object.prototype.toString.call(pParamJSON)) {
        // LOG('fnOpenUniversalWin=>fnOpenWin====3');
        fnAddAttributesFromOtherObj(_conf, pParamJSON);
    }
    // LOG('fnOpenUniversalWin=>fnOpenWin====4  conf===='+JSON.stringify(_conf));
    api.openFrame(_conf);
}

function fnOpenFrameGroup(pParamJSON, pCallback) {
    var frameY = 0;
    if (window.headerHeight) {
        frameY = window.headerHeight;
    }
    var _conf = {
        scrollEnabled: true,
        rect: {
            x: 0,
            y: frameY,
            w: 'auto',
            h: 'auto'
        },
        index: 0,
    };
    if ('[object Object]' == Object.prototype.toString.call(pParamJSON)) {
        fnAddAttributesFromOtherObj(_conf, pParamJSON);
    }
    LOG('fnOpenFrameGroup _conf==' + JSON.stringify(_conf));
    api.openFrameGroup(_conf, function(ret, err) {
        if ('function' === typeof pCallback) {
            pCallback(ret, err);
        }
    });
}
/**
 * 以默认的通用Win模版方式打开Win
 * @param  {JSON} pParamJSON  必填，打开默认win需要的配置参数
 *                pParamJSON = {
 *                    name: 'login',           //Win名称,默认‘default_win’
 *                    title: '登陆',            //Win 导航条中间页面标题
 *                    // Win打开Frame时，需要额外设置的openFrame属性
                      url: './login_frame.html',  //Win启动后打开的Frame地址,默认 './'+api.winName+'_frame.html'
 *                    slidBackEnabled: false,
 *                    reload: true,
 *
 *                }
 */
function fnOpenUniversalWin(pParamJSON) {
    if ('[object Object]' !== Object.prototype.toString.call(pParamJSON)) {
        return;
    }
    var tName = pParamJSON.winName ? pParamJSON.winName : 'default_win';
    var tParam = {
        name: tName,
        url: 'widget://html/default_win.html',
        pageParam: {
            title: pParamJSON.title,
            attributes: pParamJSON
        }
    }
    fnOpenWin(tParam);
}
// 延迟1000秒关闭win窗口
function fnDelayCloseWin(pName, pDelayTime) {
    var tName = pName;
    var tDuration = 1000;
    if ('number' === typeof pDelayTime) {
        tDuration = pDelayTime;
    }
    setTimeout(function() {
        api.closeWin({
            name: tName,
            animation: {
                type: 'none'
            }
        });

    }, tDuration);
}

function fnDelayCloseFrame(pName, pDelayTime) {
    var tName = pName;
    var tDuration = 1000;
    if ('number' === typeof pDelayTime) {
        tDuration = pDelayTime;
    }
    setTimeout(function() {
        api.closeFrame({
            name: tName,
            animation: {
                type: 'none'
            }
        });

    }, tDuration);
}

/**
 * 以frame方式打开sheet模版
 * @param  {JSON} pParamJSON  必填，打开默认win需要的配置参数
 *                pParamJSON = {
 *                    title: '登陆',               //选填，字符串，sheet标题栏标题
                      buttons: ['男'，'女'],       //必填，数组格式，sheet按钮区按钮内容
                      name: 'select_frame',       //选填，打开的frameName
                      cb_win: api.winName,        //选填，字符串，回调函数所在win
                      cb_frm: api.frameName,      //选填，字符串，回调函数所在frame
                      cb_fun: 'fnSheetCallback'   //必填，字符串，回调函数的函数名称.fnSheetCallback(pIndex);
                                                            // index     //按钮点击返回值，数组对应按钮点击事件,0对应数组按钮的0
 *                    default: 0,     //选填，数值，启动后默认高亮的按钮
 *                }
 */
function fnOpenSheet(pParamJSON) {
    var tName = pParamJSON.name ? pParamJSON.name : 'sheet';
    api.openFrame({
        name: tName,
        url: 'widget://html/template_sheet.html',
        bgColor: 'rgba(0,0,0,0)',
        animation: {
            type: 'movein',
            subType: 'from_bottom'
        },
        pageParam: pParamJSON
    });
}
/**
 * 以frame方式打开model模版
 * @param  {JSON} pParamJSON  必填，打开默认win需要的配置参数
 *                pParamJSON = {
 *                    title: '登陆',               //选填，字符串，sheet标题栏标题
                      buttons: ['男'，'女'],       //必填，数组格式，sheet按钮区按钮内容
                      name: 'select_frame',       //选填，打开的frameName
                      cb_win: api.winName,        //选填，字符串，回调函数所在win
                      cb_frm: api.frameName,      //选填，字符串，回调函数所在frame
                      cb_fun: 'fnSheetCallback'   //必填，字符串，回调函数的函数名称.fnSheetCallback(pIndex);
                                                            // index     //按钮点击返回值，数组对应按钮点击事件,0对应数组按钮的0
 *                    default: 0,     //选填，数值，启动后默认高亮的按钮
 *                }
 */
function fnOpenModel(pParamJSON) {
    var tName = pParamJSON.name ? pParamJSON.name : 'model';
    api.openFrame({
        name: tName,
        url: 'widget://html/template_model.html',
        bgColor: 'rgba(0,0,0,0)',
        animation: {
            type: 'fade'
        },
        pageParam: pParamJSON
    });
}

/**
 * 以frame方式打开日期选择器模版
 * @param  {JSON} pParamJSON  必填，打开默认win需要的配置参数
 *                pParamJSON = {
 *                    title: '登陆',               //选填，字符串，日期选择器页面标题栏标题
 *                    name: 'data_selector',      //选填，字符串，日期选择器页面frame名
                      cb_win: api.winName,        //回调函数所在win;
                      cb_frm: api.frameName,      //回调函数所在frame
                      cb_fun: 'fnSelectedCallback'             //必填，字符串，回调函数的函数名称.fnSelectedCallback(year,month,date);
                                                               // index     //按钮点击返回值，数组对应按钮点击事件,0对应数组按钮的0
 *                    default: '2017-08-21',      //选填，字符串，默认的选择日期
 *                    minNum: '1999-12-14',       //选填，字符串，限制的最小日期数值
 *                    maxNum: '2017-08-21',       //选填，字符串，限制的最大日期数值
 *                }
 */
function fnOpenDateSelector(pParamJSON) {
    var tName = pParamJSON.name ? pParamJSON.name : 'data_selector';
    api.openFrame({
        name: tName,
        url: 'widget://html/template_selector_date.html',
        bgColor: 'rgba(0,0,0,0)',
        animation: {
            type: 'movein',
            subType: 'from_bottom'
        },
        pageParam: pParamJSON
    });
}

/******************************************
                底层服务类方法
******************************************/

//服务API
var DEBUG = true;
//日志函数
function LOG(pString) {
    if (DEBUG) {
        console.log('【' + api.winName + '__' + api.frameName + '】:' + pString);
    }
}

//安卓keyBack 快速点击二次退出APP
function ExitAppByKeyBack2() {
    var BACKSTATUS = false;
    api.addEventListener({
        name: 'keyback'
    }, function(ret, err) {
        if (BACKSTATUS) {
            api.closeWidget({
                silent: true
            });
        } else {
            BACKSTATUS = true;
            api.toast({
                msg: '再按一次退出APP',
                duration: 1500,
                location: 'bottom'
            });
        }
        setTimeout(function() {
            BACKSTATUS = false;
        }, 1500);
    });
}

//时间戳转换
//时间戳转日期格式
function fnStampToDate(pStamp, pSign) {
  var tCurrentTime = new Date(pStamp);
  var tYear = tCurrentTime.getFullYear();
  var tMonth = fix(tCurrentTime.getMonth() + 1, 2);
  var tDate = fix(tCurrentTime.getDate(), 2);
  var tHours = fix(tCurrentTime.getHours(), 2);
  var tMinutes = fix(tCurrentTime.getMinutes(), 2);
  var tSeconds = fix(tCurrentTime.getSeconds(), 2);
  if (pSign == 'hours') {
    return tYear + '-' + tMonth + '-' + tDate + ' ' + tHours + ':' + tMinutes;
  }
  if (pSign == 'mins') {
    return tYear + '-' + tMonth + '-' + tDate + ' ' + tHours + ':' + tMinutes + ':00';
  }
  if (pSign == 'month') {
    return tMonth + '-' + tDate;
  }
  if (pSign == 'sec') {

    return tYear + '-' + tMonth + '-' + tDate + ' ' + tHours + ':' + tMinutes + ':' + tSeconds;
  }
  return tYear + '-' + tMonth + '-' + tDate
}

//日期加0
function fix(num, length) {
    return ('' + num).length < length ? ((new Array(length + 1)).join('0') + num).slice(-length) : '' + num;
}


//AJAX请求封装
function SERVICE() {

    //内部作用域内全局变量
    var _service = {};
    // var tBaseUrl = api.getPrefs({
    //     key: 'baseUrl',
    //     sync: true
    // });
    // if(!tBaseUrl) {
    //     tBaseUrl = 'http://218.247.190.10:9001';
    // }
    // var _baseUrl = tBaseUrl+'/lvju/api';
  //   var _baseUrl="http://192.168.30.139:9090/wanda-background/";
    //var _baseUrl="http://192.168.30.154:81/wanda-background/";
    //  var _baseUrl="http://192.168.30.156:8201/wanda-background/";
    //正式地址
     var _baseUrl = "http://47.95.2.175/wanda/";
  //测试地址2
  //  var _baseUrl = "http://111.26.198.81:9093/wanda/"
    //测试地址
  //var _baseUrl = "http://tengjiesoft.vicp.io/wanda/";
  //助理测试地址
  //var _baseUrl = "http://192.168.20.142:8080/wanda-background/"
  //抽奖
//  var _baseUrl = "http://192.168.20.143:8080/wanda-background/"
    //加密模块
    var _mSignature = api.require('signature');
    //设备信息
    // var _reqID = api.loadSecureValue({ key: 'appId' , sync: true });
    // var _reqKey = api.loadSecureValue({ key: 'appKey' , sync: true });
    var _reqID = ' A6051055100500';
    var _reqKey = 'BE43294D-D1DE-7CF2-0619-8EE4EB1572B5';
    var _termId = api.deviceId;
    var _custId = "";
    if(USER){
      if(USER.Get('custId',true)){
        _custId = USER.Get('custId',true)
      }
    }

    /*  进度状态显示  */
    var _loading = new Loading();
    _service.ShowProgress = function() {
        _loading.Show();
    }
    _service.CloseProgress = function() {
        _loading.Close();
    }

    /**
     * [save 保存数据到本地缓存]
     * @param  {[String]} pkey  [键名]
     * @param  {[JSON/String]} pData [键值，JSON格式或字符串格式]
     * @return {[无]}       [返回值：无]
     */
    _service.Save = function(pkey, pData) {
        var tData = pData;
        if ('object' === typeof pData) {
            tData = JSON.stringify(pData)
        }
        api.setPrefs({
            key: pkey,
            value: tData
        });
    }

    /**
     * [Load 从本地缓存读取数据]
     * @param  {[String]} pkey [数据缓存时的键名]
     * @return {[JSON]}      [JSON格式的数据对象或空字符串]
     */
    _service.Load = function(pkey) {
        var tDataStr = api.getPrefs({
            sync: true,
            key: pkey
        });
        var tData = '';
        if (tDataStr) {
            tData = JSON.parse(tDataStr);
        }
        return tData;
    }

    _service.SHA1 = function(pValue) {
        if ('string' != typeof pValue) {
            return '';
        } else {
            var tEncryptStr = _mSignature.sha1Sync({
                data: pValue
            });
            return tEncryptStr;
        }
    }

    _service.MD5 = function(pValue) {
        if ('string' != typeof pValue) {
            return '';
        } else {
            var tEncryptStr = _mSignature.md5Sync({
                data: pValue
            });
            return tEncryptStr;
        }
    }


    //网络请求服务部分

    //获取请求头
    function _getHeaders(pHeader) {

        var tNow = new Date().getTime() + '';
        var tReqKeyStr = _reqID + 'UZ' + _reqKey + 'UZ' + tNow;
        //通用接口加密key
        var tReqKey = _mSignature.sha1Sync({
            data: tReqKeyStr,
            uppercase: true
        });

        // LOG('加密前str==' + tReqKeyStr +'____加密后 str==' + tReqKey);

        var tHeaders = {
                // 'content-Type': 'application/json',
                'reqID': _reqID,
                'reqDate': tNow,
                'reqKey': tReqKey,
                'termId': _termId,
                'custId':_custId
                    // 'reqKey': 'test123'
            }
            // var _str = Math.floor(Math.random() * 1000 + 1) + '';
        var tUser = api.getPrefs({
            key: 'userInfo',
            sync: true
        });
        if (tUser) {
            var tUserJSON = JSON.parse(tUser);
            var tUID = tUserJSON.custId;
            var tToken = tUserJSON.tokenId;
            var tTokenStr = tUID + 'UZ' + tToken + 'UZ' + tNow;
            var tTokenKey = _mSignature.sha1Sync({
                data: tTokenStr
            });
            tHeaders.UID = tUID;
            tHeaders.Token = tTokenKey;
        }

        return tHeaders;
    }

    //响应参数统一异常处理
    function _exceptionHanding(ret, err, pCallback) {
        var _callback = function() {};
        if ('function' === typeof pCallback) {
            _callback = pCallback;
        }
        //首先判断请求成功或失败
        if (ret) {
            var tStatus;
            if(ret.status){
              tStatus = ret.status;
            }
            if(ret.errcode){
              tStatus = ret.errcode;
            }
            if ('object' !== typeof(ret.data)) {
                ret.data = {};
            }
            switch (tStatus) {
                case '200': // 请求成功
                case '400': // 请求失败
                    _callback(ret, err); //服务器成功响应（正确或错误的回调）
                    break;
                case '404': // 权限认证失败
                case '500':
                    ret.data.errorStatus = '500';
                    ret.data.errorMessage = '服务器错误，请稍后再试';
                    _callback(ret, err);
                    break;
                case '5001':
                    _callback();//无响应参数回调，仅供回调方法执行一些需要回调触发的逻辑，如关闭progress，按钮点击状态等
                    if(USER.Get('custId',true)){
                      api.alert({
                          title: '系统提示',
                          msg: '该账号已经在别处登录',
                      }, function(ret, err){
                          if( ret ){
                            //退出
                            USER.Clear();
                            //这里添加登录后的逻辑
                            api.execScript({
                                name: 'root',
                                script: 'fnGetUserStatus();'
                            });
                            api.execScript({
                                name: 'root',
                                script: 'fnStopajpush();'
                            });
                            setTimeout(function(){
                                api.rebootApp();
                            },300)
                          }else{
                               console.log( JSON.stringify( err ) );
                          }
                      });
                    }
                    break;
                default:
                    //其他未知错误
                    ret.data.errorStatus = tStatus;
                    ret.data.errorMessage = '本次请求失败，请稍后再试';
                    _callback(ret, err);
            }
        } else {
            _callback(ret, err); //回调方法中无须再对err错误进行解析，再本函数方法中统一执行，仅执行一些需要回调触发的逻辑，如关闭progress，按钮点击状态等即可
            var errMsg = !!(err && err.errmsg) ? err.errmsg : '请求失败，请稍后再试';
            var tCacheErr = api.getPrefs({
                key: 'errorCode',
                sync: true
            });
            if ('number' !== typeof tCacheErr || err.errcode != tCacheErr) {
                api.setPrefs({
                    key: 'errorCode' + err.errcode,
                    value: err.errcode
                })
                api.alert({
                    title: '系统提示',
                    msg: errMsg,
                }, function(ret, err) {
                    api.removePrefs({
                        key: 'errorCode' + err.errcode
                    });
                });
            } else {
                setTimeout(function() {
                    api.removePrefs({
                        key: 'errorCode' + err.errcode
                    });
                }, 3000);
            }
        }
    }

    //基础通用请求方法封装
    function fnRequestData(pPartUrl, pHeaders, pMethod, pData, pCallback) {
        var tUrl = _baseUrl + pPartUrl;
        var tHeaders = pHeaders ? pHeaders : _getHeaders();
        var tAjax = {
            url: tUrl,
            method: pMethod,
            headers: tHeaders,
            data: pData,
            timeout: 30000
        }

        // LOG('AJAX' + pMethod + '请求：URL=' + tUrl + '____headers=' + JSON.stringify(tHeaders) + '____data=');
        var tCode = api.ajax(tAjax, function(ret, err) {
            LOG('AJAX请求:\n' + JSON.stringify(tAjax) + '\n返回结果:' + '\n成功响应数据:' + JSON.stringify(ret) + '\n失败响应数据:' + JSON.stringify(err));
            _exceptionHanding(ret, err, pCallback);
        });
    }

    /**
     * [POST POST方法,不发送文件]
     * @param {[type]} pPartUrl  [必填，部分请求路径]
     * @param {[type]} pValues   [选填，请求参数对象]
     * @param {[type]} pCallback [选填，回调函数]
     * @param {[type]} pSet      [选填，补充请求设置参数]
     */
    _service.POST = function(pPartUrl, pValues, pCallback) {
        //请求参数
        var tData = '';
        if ('object' == typeof pValues) {
            tData = {
                values: pValues
            }
        } else if ('string' == typeof pValues && pValues.length) {
            tData = {
                body: pValues
            };
        }

        fnRequestData(pPartUrl, '', 'post', tData, pCallback)
    }

    /**
     * [POST POST方法,含发送文件]
     * @param {[type]} pPartUrl  [必填，部分请求路径]
     * @param {[type]} pValues   [选填，请求参数对象]
     * @param {[type]} pCallback [选填，回调函数]
     * @param {[type]} pSet      [选填，补充请求设置参数]
     */
    _service.POSTFiles = function(pPartUrl, url, pCallback, pSet) {
        //请求参数
        var tData = {};

        tData = {
            // body: JSON.stringify(pValues),
            files: {
                file: url
            }
        };
        fnRequestData2(pPartUrl, '', 'post', tData, pCallback, pSet);
        //上传图片请求
        function fnRequestData2(pPartUrl, pMethod, pData, pCallback, pSet) {
            var tUrl = _baseUrl + pPartUrl;
            var tHeaders = _getHeaders();
            delete tHeaders["content-Type"];
            var tAjax = {
                    url: tUrl,
                    method: pMethod,
                    headers: tHeaders,
                    data: pData,
                    timeout: 45
                }
                //自定义AJAX请求设置（JSON格式）
            if (pSet) {
                for (var key in pSet) {
                    tAjax[key] = pSet[key];
                }
            }
            LOG("tAjax====" + JSON.stringify(tAjax));
            // LOG('AJAX' + pMethod + '请求：URL=' + tUrl + '____headers=' + JSON.stringify(tHeaders) + '____data=');
            var tCode = api.ajax(tAjax, function(ret, err) {
                api.hideProgress();
                LOG('AJAX' + pMethod + '请求：URL=' + tUrl + '返回结果:' + '__ret=' + JSON.stringify(ret) + '__err' + JSON.stringify(err));
                _exceptionHanding(ret, err, tAjax, pCallback);
            });
        }
    }


    /*
     * [POST 便利GET方法]
     * @param {[String]} pPartUrl  [必填，部分请求路径]
     * @param {[Function]} pCallback [回调函数function(ret,err){}]
     */
    _service.GET = function(pPartUrl, pCallback) {
        fnRequestData(pPartUrl, '', 'get', '', pCallback);
    }
    return _service;
}
